package com.example.draggableview;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;
import android.widget.TextView;

/**
 * 自定义可以拖拽排序的布局类
 * 
 * @author Lucher
 * 
 */
public class DraggableSortLayout extends LinearLayout implements OnLongClickListener {

	private static final String TAG = "DraggableSortLayout";

	// 子view之间的间距
	private static final int VIEW_MARGIN = 5;
	private AccelerateInterpolator acInterpolator = new AccelerateInterpolator();

	// 对应的号码
	private int number;
	// 上一个x坐标，用来作为刷新拖拽图标的参照
	private int oldX = 0;
	// 拖拽图标拖动时的x坐标
	private int startX = 0;

	// 拖动状态，初始状态和拖动状态以及拖动结束
	private static int STATE_IDLE = 1;
	private static int STATE_DRAG = 2;
	// 当前拖动状态
	private int state = STATE_IDLE;

	// 当前拖动的图标，图标信息，顺序号,x坐标
	private View currentDragView;
	private ViewInfo currentDragViewInfo;
	private int currentDragOrder;
	private int currentDragViewX;

	// 拖拽图标上一个x坐标
	private int lastDragViewX;

	private DragListener mListener;
	private Context mContext;

	/**
	 * 存放所有子视图
	 */
	private List<ViewInfo> mViewList;

	/**
	 * 当前动画数量
	 */
	private int currentAnimation;

	public DraggableSortLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
	}

	/**
	 * 根据单词数组初始化视图
	 * 
	 * @param number
	 * @param words
	 */
	public void init(int number, String[] words) {
		// TODO Auto-generated method stub
		this.number = number;
		mViewList = new ArrayList<ViewInfo>();

		int size = words.length;
		for (int i = 0; i < size; i++) {
			TextView view = new TextView(mContext);
			DraggableLayoutParams lp = new DraggableLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
			view.setLayoutParams(lp);
			view.setText(words[i]);
			view.setTextSize(60);
			view.setBackgroundResource(R.drawable.tv_bg_normal);
			this.addView(view);

			ViewInfo info = new ViewInfo();
			info.view = view;
			info.text = words[i];
			info.width = -1;
			info.left = -1;
			info.order = i;
			mViewList.add(info);

			view.setOnLongClickListener(this);
		}
	}

	/**
	 * 设置拖拽接口
	 * 
	 * @param listener
	 */
	public void setDragListener(DragListener listener) {
		mListener = listener;
	}

	@Override
	protected void onLayout(boolean arg0, int l, int t, int r, int b) {
		Log.d(TAG, "layout..........................");
		final int count = mViewList.size();
		int childLeft = getPaddingLeft();
		int childTop = getPaddingTop();
		for (int i = 0; i < count; i++) {
			ViewInfo info = this.getViewInfoAt(i);
			View child = info.view;
			DraggableLayoutParams lp = (DraggableLayoutParams) child.getLayoutParams();

			int width = child.getMeasuredWidth();
			int height = child.getMeasuredHeight();

			if (isEndDrag()) {
				childLeft += VIEW_MARGIN;
				info.left = lp.left = childLeft;
				lp.top = childTop;
				info.width = lp.width = width;
				lp.height = height;

				child.layout(childLeft, childTop, childLeft + width, childTop + height);
				childLeft += width;
				Log.e(TAG, childLeft + "," + childTop + "," + (childLeft + width) + "," + (childTop + height));
			} else {
				child.layout(lp.left, lp.top, lp.left + width, lp.top + height);
			}
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		switch (event.getAction() & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_MOVE:
			handleMoveEvent(event);
			break;
		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_CANCEL:
			if (state == STATE_DRAG) {
				// 拖动状态下进行了移动的情况
				endDrag();
			}
			break;
		}

		return true;
	}

	/**
	 * 处理move事件
	 * 
	 * @param event
	 */
	private void handleMoveEvent(MotionEvent event) {

		// TODO Auto-generated method stub
		if (state == STATE_DRAG) {
			int distance = oldX - startX;// 触摸点与文本左边距离
			DraggableLayoutParams lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
			lastDragViewX = currentDragViewX;
			currentDragViewX = (int) event.getX();
			lp.left = currentDragViewX - distance;
			currentDragView.layout(lp.left, lp.top, lp.left + currentDragView.getWidth(), lp.top + currentDragView.getHeight());

			adjustViewPosition();
		}
	}

	@Override
	public boolean onInterceptTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (state == STATE_DRAG) {
			switch (event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_UP:
			case MotionEvent.ACTION_CANCEL:
				// 拖动状态，但没有移动的情况
				endDrag();
				break;
			}

			return true;
		} else {
			switch (event.getAction() & MotionEvent.ACTION_MASK) {
			case MotionEvent.ACTION_DOWN:
				oldX = (int) event.getX();
				break;
			}
		}
		return false;

	}

	/**
	 * 根据图标的当前位置，调整图标的位置
	 */
	private void adjustViewPosition() {
		ViewInfo leftViewInfo = null;// 左边的view
		ViewInfo rightViewInfo = null;// 右边的view
		if (currentDragOrder != 0) {
			leftViewInfo = mViewList.get(currentDragOrder - 1);
		}
		if (currentDragOrder != mViewList.size() - 1) {
			rightViewInfo = mViewList.get(currentDragOrder + 1);
		}

		boolean isSwapWithLeft = checkIfSwapWithLeft(copyViewInfo(currentDragViewInfo), copyViewInfo(leftViewInfo)); // 是否需要和左边视图交换
		boolean isSwapWithRight = checkIfSwapWithRight(copyViewInfo(currentDragViewInfo), copyViewInfo(rightViewInfo)); // 是否需要和右边视图交换

		if (isSwapWithLeft) {
			currentAnimation++;

			final ViewInfo leftViewInfoCopy = copyViewInfo(leftViewInfo);
			final ViewInfo currentDragViewInfoCopy = copyViewInfo(currentDragViewInfo);

			TranslateAnimation translateAnimation = new TranslateAnimation(0, currentDragViewInfoCopy.width + VIEW_MARGIN, 0, 0);
			translateAnimation.setDuration(300);
			translateAnimation.setInterpolator(acInterpolator);
			final View view = leftViewInfoCopy.view;
			DraggableLayoutParams lp = (DraggableLayoutParams) view.getLayoutParams();
			lp.left = leftViewInfoCopy.left;
			view.setLayoutParams(lp);
			final int distanceX = leftViewInfoCopy.left + currentDragViewInfoCopy.width + VIEW_MARGIN;
			view.clearAnimation();
			view.startAnimation(translateAnimation);
			translateAnimation.setAnimationListener(new AnimationListener() {
				@Override
				public void onAnimationStart(Animation animation) {
				}

				@Override
				public void onAnimationRepeat(Animation animation) {
				}

				@Override
				public void onAnimationEnd(Animation animation) {
					view.clearAnimation();
					DraggableLayoutParams lp = (DraggableLayoutParams) view.getLayoutParams();
					lp.left = distanceX;
					view.setLayoutParams(lp);
					view.requestLayout();
					currentAnimation--;
				}
			});

			swapViewInfoByOrder(currentDragOrder, leftViewInfo.order);
		}

		if (isSwapWithRight) {
			currentAnimation++;

			final ViewInfo rightInfoCopy = copyViewInfo(rightViewInfo);
			final ViewInfo currentDragViewInfoCopy = copyViewInfo(currentDragViewInfo);

			TranslateAnimation translateAnimation = new TranslateAnimation(0, -currentDragViewInfoCopy.width - VIEW_MARGIN, 0, 0);
			translateAnimation.setDuration(300);
			translateAnimation.setInterpolator(acInterpolator);
			final View view = rightInfoCopy.view;
			DraggableLayoutParams lp = (DraggableLayoutParams) view.getLayoutParams();
			lp.left = rightInfoCopy.left;
			view.setLayoutParams(lp);
			final int distanceX = rightInfoCopy.left - currentDragViewInfoCopy.width - VIEW_MARGIN;
			view.clearAnimation();
			view.startAnimation(translateAnimation);
			translateAnimation.setAnimationListener(new AnimationListener() {
				@Override
				public void onAnimationStart(Animation animation) {
				}

				@Override
				public void onAnimationRepeat(Animation animation) {
				}

				@Override
				public void onAnimationEnd(Animation animation) {
					view.clearAnimation();
					DraggableLayoutParams lp = (DraggableLayoutParams) view.getLayoutParams();
					lp.left = distanceX;
					view.setLayoutParams(lp);
					view.requestLayout();
					currentAnimation--;
				}
			});

			swapViewInfoByOrder(currentDragOrder, rightViewInfo.order);
		}
	}

	/**
	 * 拷贝一个视图信息
	 * 
	 * @param src
	 * @return
	 */
	private ViewInfo copyViewInfo(ViewInfo src) {
		if (src == null)
			return null;
		ViewInfo des = new ViewInfo();
		des.left = src.left;
		des.order = src.order;
		des.text = src.text;
		des.view = src.view;
		des.width = src.width;

		return des;
	}

	/**
	 * 判断是否需要和左边视图交换
	 * 
	 * @param currentDragViewInfo
	 * @param leftViewInfo
	 * @return
	 */
	private boolean checkIfSwapWithLeft(ViewInfo currentDragViewInfo, ViewInfo leftViewInfo) {
		// TODO Auto-generated method stub
		if (currentDragViewInfo == null || leftViewInfo == null) {
			return false;
		}

		if ((currentDragViewX - leftViewInfo.width / 3 < leftViewInfo.left + leftViewInfo.width && lastDragViewX - leftViewInfo.width / 3 >= leftViewInfo.left
				+ leftViewInfo.width))
			return true;

		if (currentDragViewX <= leftViewInfo.left + leftViewInfo.width + 5 && lastDragViewX > leftViewInfo.left + leftViewInfo.width + 5)
			return true;

		return false;
	}

	/**
	 * 判断是否需要和右边视图交换
	 * 
	 * @param currentDragViewInfo
	 * @param rightViewInfo
	 * @return
	 */
	private boolean checkIfSwapWithRight(ViewInfo currentDragViewInfo, ViewInfo rightViewInfo) {
		// TODO Auto-generated method stub
		if (currentDragViewInfo == null || rightViewInfo == null) {
			return false;
		}

		if (currentDragViewX + currentDragViewInfo.width / 4 > rightViewInfo.left
				&& lastDragViewX + currentDragViewInfo.width / 4 <= rightViewInfo.left)
			return true;

		if (currentDragViewX + currentDragViewInfo.width > rightViewInfo.left + rightViewInfo.width - 5
				&& lastDragViewX + currentDragViewInfo.width <= rightViewInfo.left + rightViewInfo.width - 5)
			return true;

		return false;
	}

	/**
	 * 根据顺序号交换视图信息
	 * 
	 * @param from
	 *            需要交换的源顺序号
	 * @param to
	 *            需要交换的目标顺序号
	 */
	private void swapViewInfoByOrder(int from, int to) {
		Log.d(TAG, "swapViewInfoByOrder...from=" + from + "to=" + to);
		View tempView = this.mViewList.get(from).view;
		this.mViewList.get(from).view = this.mViewList.get(to).view;
		this.mViewList.get(to).view = tempView;

		if (from < to) { // 往后拖
			mViewList.get(from).left = mViewList.get(to).left - mViewList.get(from).width - VIEW_MARGIN;
			mViewList.get(to).left = mViewList.get(from).left + mViewList.get(to).width + VIEW_MARGIN;
		} else { // 往前拖
			mViewList.get(from).left = mViewList.get(to).left + mViewList.get(from).width + VIEW_MARGIN;
			mViewList.get(to).left = mViewList.get(from).left - mViewList.get(to).width - VIEW_MARGIN;
		}

		String tempText = this.mViewList.get(from).text;
		this.mViewList.get(from).text = this.mViewList.get(to).text;
		this.mViewList.get(to).text = tempText;

		int tempWidth = this.mViewList.get(from).width;
		this.mViewList.get(from).width = this.mViewList.get(to).width;
		this.mViewList.get(to).width = tempWidth;

		currentDragOrder = to;
		currentDragViewInfo = this.mViewList.get(currentDragOrder);
		currentDragView = this.mViewList.get(currentDragOrder).view;
	}

	/**
	 * 拖动事件结束处理
	 */
	private void endDrag() {
		Log.d(TAG, "current animation=" + currentAnimation);
		state = STATE_IDLE;
		DraggableLayoutParams lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
		lp.top = getPaddingTop();
		currentDragView.setBackgroundResource(R.drawable.tv_bg_normal);
		getSortedWords();
		requestLayout();
	}

	/**
	 * 获取排好序的单词
	 */
	private void getSortedWords() {
		// TODO Auto-generated method stub
		int count = this.mViewList.size();
		String[] result = new String[count];
		for (int i = 0; i < count; i++) {
			result[i] = this.mViewList.get(i).text;
		}
		mListener.onDragEnd(number, result);
	}

	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		this.startDrag(v);
		return false;
	}

	/**
	 * 提交答案
	 * 
	 * @param result
	 */
	public boolean submit(int[] result) {

		int count = this.mViewList.size();
		if (result.length != count) {// 长度不一样则出问题了，直接返回错误
			return false;
		}

		for (int i = 0; i < count; i++) {
			TextView child = (TextView) this.mViewList.get(i).view;
			if (result[i] == 0) {
				child.setTextColor(Color.RED);
			}
		}
		return true;
	}

	/**
	 * 开始拖拽
	 * 
	 * @param view
	 */
	private void startDrag(View view) {
		state = STATE_DRAG;
		currentDragView = view;
		currentDragOrder = getOrderByView(view);
		currentDragViewInfo = this.getViewInfoAt(currentDragOrder);

		// 拖拽的时候把图标上移，效果更好
		DraggableLayoutParams lp = (DraggableLayoutParams) currentDragView.getLayoutParams();
		lp.top = getPaddingTop() - 3 > 0 ? getPaddingTop() - 3 : 0;
		currentDragView.layout(lp.left, lp.top, lp.left + currentDragView.getWidth(), lp.top + currentDragView.getHeight());

		startX = currentDragViewInfo.left;
		view.setBackgroundResource(R.drawable.tv_bg_drag);
		bringChildToFront(view);
	}

	/**
	 * 根据view获取对应的order
	 * 
	 * @param view
	 * @return
	 */
	private int getOrderByView(View view) {
		int order = -1;
		int count = this.mViewList.size();
		for (int i = 0; i < count; i++) {
			if (view == this.getViewInfoAt(i).view) {
				order = i;
				return order;
			}
		}
		return order;
	}

	/**
	 * 获取指定顺序号的子视图
	 * 
	 * @param order
	 * @return
	 */
	private ViewInfo getViewInfoAt(int order) {
		return this.mViewList.get(order);
	}

	/**
	 * 是否结束拖拽
	 * 
	 * @return
	 */
	private boolean isEndDrag() {
		return (state == STATE_IDLE && currentAnimation == 0);
	}

	/**
	 * 监听拖拽状态
	 * 
	 * @author lucher
	 * 
	 */
	public interface DragListener {
		/**
		 * 拖拽开始
		 */
		public void onDragStart();

		/**
		 * 拖拽结束
		 * 
		 * @param number
		 * @param result
		 */
		public void onDragEnd(int number, String[] result);
	}

	/**
	 * 自定义布局参数类
	 * 
	 * @author Lucher
	 * 
	 */
	private class DraggableLayoutParams extends LinearLayout.LayoutParams {

		// 距离左边和上边距离
		int left, top;

		public DraggableLayoutParams(int width, int height) {
			super(width, height);
		}
	}

	/**
	 * 自定义视图信息类
	 * 
	 * @author Lucher
	 * 
	 */
	private class ViewInfo {
		int order; // 顺序号
		String text; // 文本信息
		int left;
		int width;
		View view;

		public String toString() {
			return "order:" + order + ",left:" + left + ",width:" + width + ",text:" + text;
		}
	}
}
